package com.ruyuan.seckill.service.impl;

import com.ruyuan.seckill.cache.Cache;
import com.ruyuan.seckill.domain.Buyer;
import com.ruyuan.seckill.domain.MemberAddress;
import com.ruyuan.seckill.domain.dto.OrderDTO;
import com.ruyuan.seckill.domain.enums.CheckedWay;
import com.ruyuan.seckill.domain.enums.ClientType;
import com.ruyuan.seckill.domain.vo.CartView;
import com.ruyuan.seckill.domain.vo.CheckoutParamVO;
import com.ruyuan.seckill.domain.vo.TradeVO;
import com.ruyuan.seckill.service.CartReadManager;
import com.ruyuan.seckill.service.CheckoutParamManager;
import com.ruyuan.seckill.service.GoodsClient;
import com.ruyuan.seckill.service.MemberAddressClient;
import com.ruyuan.seckill.service.MemberClient;
import com.ruyuan.seckill.service.ShippingManager;
import com.ruyuan.seckill.service.TradeCreator;
import com.ruyuan.seckill.service.TradeIntodbManager;
import com.ruyuan.seckill.service.TradeManager;
import com.ruyuan.seckill.service.TradeSnCreator;
import com.ruyuan.seckill.utils.JsonUtil;
import com.ruyuan.seckill.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

/**
 * 交易管理实现类
 */
@Service
@Slf4j
public class TradeManagerImpl implements TradeManager {

    protected final CheckoutParamManager checkoutParamManager;

    protected final CartReadManager cartReadManager;

    protected final ShippingManager shippingManager;

    protected final GoodsClient goodsClient;


    protected final TradeSnCreator tradeSnCreator;

    protected final MemberAddressClient memberAddressClient;

    protected final MemberClient memberClient;

    protected final TradeIntodbManager tradeIntodbManager;
    private final Cache cache;
    private final RedisTemplate redisTemplate;

    public TradeManagerImpl(CheckoutParamManager checkoutParamManager, CartReadManager cartReadManager, ShippingManager shippingManager, GoodsClient goodsClient, TradeSnCreator tradeSnCreator, MemberAddressClient memberAddressClient, MemberClient memberClient, TradeIntodbManager tradeIntodbManager, Cache cache, RedisTemplate redisTemplate) {
        this.checkoutParamManager = checkoutParamManager;
        this.cartReadManager = cartReadManager;
        this.shippingManager = shippingManager;
        this.goodsClient = goodsClient;
        this.tradeSnCreator = tradeSnCreator;
        this.memberAddressClient = memberAddressClient;
        this.memberClient = memberClient;
        this.tradeIntodbManager = tradeIntodbManager;
        this.cache = cache;
        this.redisTemplate = redisTemplate;
    }

    /**
     * 秒杀交易创建
     *
     * @param orderDTO 订单信息
     * @return
     */
    @Override
    public TradeVO seckillCreate(OrderDTO orderDTO) {
        return null;
    }

    /**
     * 秒杀交易创建
     *
     * @param clientType 客户的类型
     * @param way 购买方式
     * @return 返回交易的VO对象
     */
    @Override
    public TradeVO secKillCreate(String clientType, CheckedWay way, Integer uid) {
        // 获取用户信息字符串数据
        String buyerString = (String) cache.get(uid);
        // 将用户信息的字符串转为Buyer对象
        Buyer buyer = JsonUtil.jsonToObject(buyerString, Buyer.class);
        // 检查用户的交易结算类的属性数据是否存在 如 收获地址等数据是否存在
        CheckoutParamVO param = checkoutParamManager.getParam(uid);
        this.setClientType(clientType, uid);
        // 校验并读取购物车中选中的商品 并生成购物车对象
        CartView cartView = this.cartReadManager.getCheckedItems(way, buyer);
        // 获取会员的选中的收获地址
        MemberAddress memberAddress = this.memberAddressClient.getModel(param.getAddressId());
        // 基于交易构造器创建交易对象
        TradeCreator tradeCreator = new DefaultTradeCreator(param, cartView, memberAddress, param.getPaymentType())
                .setBuyer(buyer)
                .setTradeSnCreator(tradeSnCreator)
                .setGoodsClient(goodsClient)
                .setMemberClient(memberClient)
                .setShippingManager(shippingManager)
                .setCheckoutParamManager(checkoutParamManager);

        // 对交易对象进行一系列的合法性校验 检测配置范围-> 检测商品合法性 -> 检测促销活动合法性 -> 创建交易
        // 最后创建交易 并且生成交易流水号 以及 这笔交易下的订单的流水号 都是基于lua脚本在redis中生成的
        TradeVO tradeVO = tradeCreator.checkShipRange().checkGoods().checkPromotion().createTrade();
        tradeVO.setBuyer(buyer);
        tradeVO.setWay(way);
        // redis库存扣减
        log.info("start deduction stock");
        // 最后基于lua脚本对交易关联的订单对应的商品可销售库存以及商品的SKU可销售库存进行库存扣减
        this.tradeIntodbManager.seckillStockDeduction(tradeVO);
        log.info("deduction stock end");

        return tradeVO;
    }


    /**
     * 设置client type
     *
     * @param client
     */
    protected void setClientType(String client, Integer uid) {

        // 如果客户端类型为空，那么需要判断是否是wap访问
        if (StringUtil.isEmpty(client) && StringUtil.isWap()) {
            client = "WAP";
        }

        ClientType type = ClientType.valueOf(client);

        this.checkoutParamManager.setClientType(type.getClient(), uid);
    }
}
